#include "MenuBuilder.h"

#include "Bridge.h"
#include "Configuration.h"

/**
 * @brief MenuBuilder::loadFromConfig Set the menu builder to be customizable
 * @param id The id of menu builder. It should be the same on every same menu.
 */
void MenuBuilder::loadFromConfig() {
  this->id =
      parent()->metaObject()->className();  // Set the ID first because the
                                            // following subroutine will use it
  Config()->registerMenuBuilder(
      this,
      _containers.size());  // Register it to the config so the customization
                            // dialog can get the text of actions here.
}

QMenu* MenuBuilder::addMenu(QMenu* submenu, BuildCallback callback) {
  addBuilder(new MenuBuilder(submenu->parent(), [submenu, callback](QMenu*) {
    submenu->clear();
    return callback(submenu);
  }))->addMenu(submenu);
  return submenu;
}

QMenu* MenuBuilder::addMenu(QMenu* submenu, MenuBuilder* builder) {
  addBuilder(new MenuBuilder(submenu->parent(), [submenu, builder](QMenu*) {
    submenu->clear();
    return builder->build(submenu);
  }))->addMenu(submenu);
  return submenu;
}

/**
 * @brief MenuBuilder::getText Get the title of id-th element. This function is
 * called by CustomizeMenuDialog to initialize the dialog.
 * @param id The index of the element in "_containers"
 * @return The title, or empty. If it is empty, that element will not appear in
 * the CustomizeMenuDialog.
 */
QString MenuBuilder::getText(size_t id) const {
  const Container& container = _containers.at(id);
  switch (container.type) {
    case Container::Action:
      return container.action->text();
    case Container::Menu:
      return container.menu->title();
    case Container::Builder: {
      if (container.builder->_containers.size() == 1)
        return container.builder->getText(
            0);  // recursively get the text inside the menu builder
      else
        return QString();
    }
    default:  // separator
      return QString();
  }
}

/**
 * @brief MenuBuilder::build Build the menu with contents stored in the menu
 * builder
 * @param menu The menu to build.
 * @return true if the callback succeeds, false if the callback returns false.
 */
bool MenuBuilder::build(QMenu* menu) const {
  if (_callback && !_callback(menu)) return false;
  QMenu* submenu;
  if (id != 0)
    submenu = new QMenu(tr("More commands"), menu);
  else
    submenu = nullptr;
  for (size_t i = 0; i < _containers.size(); i++) {
    const Container& container = _containers.at(i);
    QMenu* _menu;
    if (id != 0 && container.type != Container::Separator &&
        Config()->getBool("Gui", QString("Menu%1Hidden%2").arg(id).arg(i)))
      _menu = submenu;
    else
      _menu = menu;
    switch (container.type) {
      case Container::Separator:
        _menu->addSeparator();
        break;
      case Container::Action:
        _menu->addAction(container.action);
        break;
      case Container::Menu:
        _menu->addMenu(container.menu);
        break;
      case Container::Builder:
        container.builder->build(_menu);
        break;
      default:
        break;
    }
  }
  if (id != 0 && !submenu->actions().isEmpty()) {
    menu->addSeparator();
    menu->addMenu(submenu);
  } else if (submenu) {
    delete submenu;
  }
  return true;
}
